package de.fhhof.robot.control.common;

import java.text.CharacterIterator;
import java.text.StringCharacterIterator;

import de.fhhof.robot.control.ApplicationStorage;
import de.fhhof.robot.control.ExecutionState;
import de.fhhof.robot.control.IMessage;
import de.fhhof.robot.control.InvalidOperation;
import de.fhhof.robot.control.cmd.concreate.AssemblyState;
import de.fhhof.robot.control.cmd.concreate.MessageState;
import de.fhhof.robot.control.net.IConnection;

public class Utility {
	
	private static StringBuffer strb;
	private static StringCharacterIterator sci;
	
   /** method to left pad a string with a given string to a given size. This
    *  method will repeat the padder string as many times as is necessary until
    *  the exact specified size is reached. If the specified size is less than the size of
    *  the original string then the original string is returned unchanged.
    *  Example1 - original string "cat", padder string "white", size 8 gives "whitecat".
    *  Example2 - original string "cat", padder string "white", size 15 gives "whitewhitewhcat".
    *  Example3 - original string "cat", padder string "white", size 2 gives "cat".
    *  @return String the newly padded string
    *  @param  stringToPad The original string
    *  @param  padder The string to pad onto the original string
    *  @param  size The required size of the new string
    */	
	public static String leftPad (String stringToPad, String padder, int size)
	{
		if (padder.length() == 0)
		{
			return stringToPad;
		}
		strb = new StringBuffer(size);
		sci  = new StringCharacterIterator(padder);
 
        while (strb.length() < (size - stringToPad.length()))
        {
			for (char ch = sci.first(); ch != CharacterIterator.DONE ; ch = sci.next())
			{
				if (strb.length() <  size - stringToPad.length())
				{
					strb.insert(  strb.length(),String.valueOf(ch));
				}
			}
		}
		return strb.append(stringToPad).toString();
	}
	public static String pad(String toPad,int size){
		return leftPad(toPad, "0", size);
	}
	public static boolean hasInvalidResponse(IMessage ack1, IMessage ack2){
		/** Any one of the response is null */
		if(ack1 == null || ack2 == null){
			System.out.println("Either ack1/ack2 is null");
			return true;
		}
		if(!ack1.getCommand().equals("A001")){
			System.out.println("expected ack1: A001 but got ack1: "+ ack1.getCommand());
			return true;
		}
		if(!ack2.getCommand().equals("A002")){
			System.out.println("expected ack2: A002 but got ack2: "+ ack2.getCommand());
			return true;
		}		
		return false;
	}
	public static IMessage sendMessage(IMessage msg,IConnection conn,MessageState state, AssemblyState assembly){
		
		if(!state.isSent()){
			conn.send(msg);
			state.setSent(true);
			state.setMsg(msg);
			ApplicationStorage.getAssemblyState().store(assembly, CommonConstants.STORAGE_FILE_NAME);
		}
		/** Read acknowledgment 1*/
		IMessage ack1 = null;
		if(!state.isAck1Received()){
			ack1 = conn.receive();
			if(ack1 == null){
				System.out.println("Expected ack1 but got: null");
				throw new InvalidOperation();
			}
			if(!ack1.getCommand().equals("A001")){
				System.out.println("Expected ack1: A001 but got: "+ ack1.getCommand());
				throw new InvalidOperation();
			}
			state.setAck1(ack1);
			state.setAck1Received(true);
			ApplicationStorage.getAssemblyState().store(assembly, CommonConstants.STORAGE_FILE_NAME);
		}else{
			ack1 = state.getAck1();
		}
		/** Read acknowledgment 2*/
		IMessage ack2 = null;
		if(!state.isAck2Received()){
			ack2 = conn.receive();
			if(ack2 == null){
				System.out.println("Expected ack2 but got: null");
				throw new InvalidOperation();
			}
			if(!ack2.getCommand().equals("A002")){
				System.out.println("Expected ack2: A002 but got: "+ ack2.getCommand());
				throw new InvalidOperation();
			}			
			state.setAck2(ack2);
			state.setAck2Received(true);
			ApplicationStorage.getAssemblyState().store(assembly, CommonConstants.STORAGE_FILE_NAME);
		}else{
			ack2 = state.getAck2();
		}
		if(hasInvalidResponse(ack1, ack2)){
			throw new InvalidOperation();
		}
		return ack2;
	}	
}
